#include "qrcodecreator.h"
#include "common/versions.h"
#include "encoding.h"
#include "imagecreator.h"
#include "common/stringutils.h"
#include "common/errorcorrection.h"

#include <iterator>

#include<QString>

#include <QDebug>

namespace qrcode{

QRCodeCreator::QRCodeCreator(std::string &msg, char &errorLevel,
                             std::string &modeIndicator)
    :_msg(msg),_errorLevel(errorLevel),_modeIndicator(modeIndicator)
{
    _version = SelevtSmallestVersion(modeIndicator, errorLevel, msg.length());
    StringUtils::PRINT("版本：", _version);
    Versions *qVer = new Versions();
    _remainderBits = qVer->GetRemainderBits(_version);
}


int QRCodeCreator::SelevtSmallestVersion(std::string &mode, char &level, int capacity)
{
    Versions *qVer = new Versions();
    for(int i = 0; i < 40; ++i){
        if(capacity < qVer->GetCapacity(i, mode, level)){
            return i+1;
        }
    }
}

std::pair<group, group> QRCodeCreator::BreakIntoBlock(std::vector<std::vector<char> > &codeWords)
{
    group codewordsGroup1;
    group codewordsGroup2;
    Versions *qVer = new Versions();
    std::vector<int> breakInfo = qVer->GetBreakInfo(_version, _errorLevel);
    _ECCodewordsPerBlock = breakInfo.at(0);
    block _block;
    int k = 0;
    //第一组数据
    for(int i=0; i < breakInfo.at(1); i++){
        for(int j=0; j < breakInfo.at(2); j++){
            _block.push_back(codeWords.at(k));
            k++;
        }
        codewordsGroup1.push_back(_block);
        _block.clear();
    }
    //第二组数据
    for(int i=0; i < breakInfo.at(3); i++){
        for(int j=0; j < breakInfo.at(4); j++){
            _block.push_back(codeWords.at(k));
            k++;
        }
        codewordsGroup2.push_back(_block);
        _block.clear();
    }

    std::pair<group, group> p(codewordsGroup1, codewordsGroup2);
    return p;
}

std::pair<group, group> QRCodeCreator::ECCEncoding(std::pair<group, group> &p)
{
    ErrorCorrection *qEC = new ErrorCorrection();
    block_int genePoly = qEC->GetGeneratorPolynomials(_ECCodewordsPerBlock);
    group ECCGroup1 = qEC->Ecoding(p.first, genePoly);
    group ECCGroup2 = qEC->Ecoding(p.second, genePoly);

    std::pair<group, group> tmp(ECCGroup1, ECCGroup2);
    return tmp;
}

std::vector<std::vector<char> > QRCodeCreator::InterleaveBlocks(std::pair<group, group> &codeGroup,
                                                                std::pair<group, group> &eccGroup)
{
    std::vector<std::vector<char> > msg;

    group g1;
    group g2;
    block b;

    //1.Interleave the Data Codewords
    g1 = codeGroup.first;
    g2 = codeGroup.second;
    int coll1 = 0;
    int coll2 = 0;
    if(g1.size() != 0){
        b = g1.at(0);
        coll1 = b.size();
    }
    if(g2.size() != 0){
        b = g2.at(0);
        coll2 = b.size();
    }

    int coll = coll1 > coll2 ? coll1: coll2;

    for(int i = 0; i < coll; i++){
        if(i < coll1){
            for(int j = 0; j < g1.size(); j++){
                b = g1.at(j);
                msg.push_back(b.at(i));
            }
        }

        if(i < coll2){
            for(int j = 0; j < g2.size(); j++){
                b = g2.at(j);
                msg.push_back(b.at(i));
            }
        }
    }

    //2.Interleave the Error Correction Codewords
    g1 = eccGroup.first;
    g2 = eccGroup.second;
    b = g1.at(0);
    coll = b.size();

    for(int i = 0 ; i < coll; i++){
        for(int j = 0; j < g1.size(); j++){
            b = g1.at(j);
            msg.push_back(b.at(i));
        }
        if(g2.size() != 0){
            for(int j = 0; j < g2.size(); j++){
                b = g2.at(j);
                msg.push_back(b.at(i));
            }
        }
    }

    return msg;
}

std::vector<char> QRCodeCreator::ToBitStream(std::vector<std::vector<char>> &msg)
{
    std::vector<char> bits;
    std::vector<char> tmp;
    for(int i = 0; i < msg.size(); i++){
        //qDebug() << "msg: " <<i;
        tmp = msg.at(i);
        for(int j = 0; j < tmp.size(); j++){
            //qDebug() << "tmp: " <<j;
            bits.push_back(tmp.at(j));
        }
    }

    return bits;
}


bool QRCodeCreator::Create()
{
    //1.数据编码
    Encoding *qEnc = new Encoding();
    qEnc->DoEncoding(_modeIndicator, _version, _msg, _errorLevel);
    std::vector<std::vector<char>> codeWords = qEnc->GetCodeWords();

    StringUtils::PRINT("数据码字总数：", int(codeWords.size()));

    //2.码字分组分块
    std::pair<group, group> codewordsGroup = BreakIntoBlock(codeWords);

    //3.生成纠错码
    std::pair<group, group> ECCGroup = ECCEncoding(codewordsGroup);

    //4.构造最终信息,并转换为位流
    std::vector<std::vector<char>> finalMsg = InterleaveBlocks(codewordsGroup, ECCGroup);

    //StringUtils::PRINT("完整数据：", finalMsg);
    StringUtils::PRINT("最终信息长度：", int(finalMsg.size())*8);
    StringUtils::PRINT("保留位数：", int(_remainderBits.size()));
    if(_remainderBits.size() != 0){
        finalMsg.push_back(_remainderBits);
    }
    std::vector<char> bitstream = ToBitStream(finalMsg);

    StringUtils::PRINT("位流长度：", int(bitstream.size()));

    //5.生成图形
    ImageCreator *pImage = new ImageCreator(_version, bitstream);
    pImage->setPic(pic);
    pImage->setErrorLevel(_errorLevel);
    pImage->Creator();

    return true;
}

void QRCodeCreator::PrintBits(std::vector<char> vec)
{
    QString str;
    for(int i = 0; i < vec.size(); ++i){
        str.append(vec.at(i));
    }

    qDebug() << str;
}

void QRCodeCreator::setPic(const PictureInfo &value)
{
    pic = value;
}

QRCodeCreator::~QRCodeCreator()
{
    
}

}

